Before you begin, note that, in the header, the output format of this
document is html_notebook. When you save this file, it
automatically creates another file with the same file name but with
.nb.html extension in the same directory. This is the file
you will submit as your homework solution along with the
.Rmd file.
Warnings:
- Donβt delete the
nb.html file.
- Donβt
knit your .Rmd file to
html. If you want to look at the output, just open the
nb.html in the browser. Alternatively, click on the
βPreviewβ button on top of the document.
If you delete nb.html file, you may have to create a new
.Rmd file and restart from there. If you knit your
.Rmd file to html, you will not be able to
retain any of the interactivity in the plots. This means the TA will
not be able to grade you!
The objective of this homework is to give you more practice on
interactive visualizations using plotly and
highcharter.
As always, recreate these visualizations exactly. Q1 uses
plotly while Q2-Q5 use highcharter.
Q1 (3 points)
Use mpg data set from ggplot2 to create a
static visualization and then use ggplotly() to create a
limited interactive plot.
Hint: You will need to supply only
frame. No ids used.
data(mpg, package = "ggplot2")
gg <- ggplot(mpg,
aes(x = cty, y = hwy, color = class)) +
geom_point(aes(frame = class)) +
labs(x = 'cty',
y = 'hwy') +
theme_minimal() +
theme(
legend.position = 'none'
)
ggplotly(gg)
NA
For the next four questions, you will use highcharter.
Q2 (3 points)
This example creates a heatmap similar to the one shown
here.
Use mpg data and hchart() function. We want
to create a heatmap of average highway mileage for different
class and cyl. This plot removes all the
observations with five cylinders or with 2seater class.
Also note that I am treating cyl as a character (string)
variable. This is essential for creating this plot.
I am using hc_theme_538(). Furthermore, the default
color in the heatmap is blue, which I changed using
hc_colorAxis() function that I used in the Week 10
heatmap.
data(mpg, package = "ggplot2")
mpg$cyl = as.character(mpg$cyl)
mpg2 = mpg %>%
select(cyl, class, hwy) %>%
filter(
!cyl %in% c('5') &
!class %in% c('2seater')
) %>%
group_by(class, cyl) %>%
summarise(
hwy = round(mean(hwy),2),
.groups = "drop")
stops = color_stops(colors = rev(c("#000004FF",
"#56106EFF",
"#BB3754FF",
"#F98C0AFF",
"#FCFFA4FF")))
hchart(
mpg2,
"heatmap",
hcaes(x = class, y = cyl, value = hwy),
colorKey = "hwy",
) %>%
hc_colorAxis(
min = 15,
max = 35,
stops = stops) %>%
hc_add_theme(hc_theme_538()) %>%
hc_legend(
min = 15,
max = 35,
enabled = TRUE) %>%
hc_plotOptions(
series = list(showInLegend = FALSE)
)
Q3 (3 points)
In the above plot, the tooltip shows confusing information. Below, I
modified the tooltip to present more information. The code is not at all
complicated and relies on the tooltip code we used in Week 10.
Next, I removed the X axis title and modified Y axis title.
Finally, I added a title to the plot. Note how I used four different
emojies related to cars. It doesnβt matter which car emojis you use as
long as they are related to automobiles.
data(mpg, package = "ggplot2")
mpg$cyl = as.character(mpg$cyl)
mpg2 = mpg %>%
select(cyl, class, hwy) %>%
filter(
!cyl %in% c('5') &
!class %in% c('2seater')
) %>%
group_by(class, cyl) %>%
summarise(
hwy = round(mean(hwy),2),
.groups = "drop")
stops = color_stops(colors = rev(c("#000004FF",
"#56106EFF",
"#BB3754FF",
"#F98C0AFF",
"#FCFFA4FF")))
fntltp <- JS("function(){
return 'For class ' + this.series.xAxis.categories[this.point.x] + ' with ' +
this.series.yAxis.categories[this.point.y] + ' cylinders' + ': <b>' +
Highcharts.numberFormat(this.point.value, 2)+'</b>' + ' mpg';
; }")
hchart(
mpg2,
"heatmap",
hcaes(x = class, y = cyl, value = hwy),
colorKey = "hwy",
name = "Highway Mileage"
) %>%
hc_colorAxis(
min = 15,
max = 35,
stops = stops) %>%
hc_add_theme(hc_theme_538()) %>%
hc_legend(
min = 15,
max = 35,
enabled = TRUE) %>%
hc_plotOptions(
series = list(showInLegend = FALSE)
) %>%
hc_title(text = "Highway Mileage Decreases across all the π π π π» as the Number of Cylinders Increases",
style = list(color = "black", weight = "bold")) %>%
hc_yAxis(title = list(text = "Number of Cylinders")) %>%
hc_xAxis(title = list(text = "")) %>%
hc_tooltip(formatter = fntltp)
NA
Q4 (3 points)
For this example, use a randomly selected subset of
diamonds data set from ggplot2:
?diamonds
set.seed(2020)
d1 = diamonds[sample(nrow(diamonds), 1000),]
Next use d1 to create the following plot.
I have used hc_theme_flat() for this plot.
Please use this theme for your plot too! You can add a
theme to the plot using hc_add_theme() function. Wherever
the word diamond appeared in the plot, I replaced it with the diamond
emoji.
Point colors in this graph are mapped to clarity. Check
out all the variables in this data set by typing ?diamonds
in the console.
hchart(
d1,
"scatter",
hcaes(x=carat, y=price, group=clarity)
) %>%
hc_add_theme(hc_theme_flat()) %>%
hc_xAxis(
title = list(text = "Weight of π in Carats")) %>%
hc_yAxis(
title = list(text = "Price of π")) %>%
hc_title(text = "Variation in Prices for π Increases with Carats",
style = list(color = "black", weight = "bold"))
NA
NA
Q5 (3 points)
Recreate the plot in Q2 using hchart(). I used
hc_theme_economist(). You can use any theme you want. You
can check out the themes here. I
used economics dataset from ggplot2. Learn
more about the variables in the dataset by typing
?economics in the console.
data(economics, package = "ggplot2")
econ2 = economics %>%
select(date, unemploy)
hchart(
econ2,
"line",
hcaes(x=date, y=unemploy)) %>%
hc_add_theme(hc_theme_economist()) %>%
hc_xAxis(
title = list(text = "Date")) %>%
hc_yAxis(
title = list(text = "Unemployment in '000"),
min = 2000,
max = 16000,
alignTicks = FALSE,
tickInterval = 2000) %>%
hc_title(text = "Unemployment Peaked after the Financial Crisis",
style = list(color = "black", weight = "bold", fontSize = 18),
align = 'center') %>%
hc_tooltip(pointFormat = "<div style=fill:#6794a7>β</div> Unemployment: <div style=font-weight:bold>{point.y}</div>")
NA
NA
Bonus plot (Not graded)
This is the same plot as above except if you hover mouse pointer over
the peak of unemployment, the tooltip will show more information. Once
again, this is a simple trick and doesnβt require any advanced
coding.
LS0tCnRpdGxlOiAiSG9tZXdvcmsgMyIKc3VidGl0bGU6ICJEQSA2MjMzIgphdXRob3I6ICJBZGQgeW91ciBuYW1lIGFuZCBhYmMxMjMiCmRhdGU6ICIyNSBPY3RvYmVyIDIwMjMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBjb3NtbwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoaGlnaGNoYXJ0ZXIpCmxpYnJhcnkoZHBseXIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgpCZWZvcmUgeW91IGJlZ2luLCBub3RlIHRoYXQsIGluIHRoZSBoZWFkZXIsIHRoZSBvdXRwdXQgZm9ybWF0IG9mIHRoaXMgZG9jdW1lbnQgaXMgYGh0bWxfbm90ZWJvb2tgLiBXaGVuIHlvdSBzYXZlIHRoaXMgZmlsZSwgaXQgYXV0b21hdGljYWxseSBjcmVhdGVzIGFub3RoZXIgZmlsZSB3aXRoIHRoZSBzYW1lIGZpbGUgbmFtZSBidXQgd2l0aCBgLm5iLmh0bWxgIGV4dGVuc2lvbiBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuIFRoaXMgaXMgdGhlIGZpbGUgeW91IHdpbGwgc3VibWl0IGFzIHlvdXIgaG9tZXdvcmsgc29sdXRpb24gYWxvbmcgd2l0aCB0aGUgYC5SbWRgIGZpbGUuIAoKPGZvbnQgY29sb3IgPSAicmVkIj4gCioqV2FybmluZ3MqKjogCgoxKSBEb24ndCBkZWxldGUgdGhlIGBuYi5odG1sYCBmaWxlLiAKMikgRG9uJ3QgYGtuaXRgIHlvdXIgYC5SbWRgIGZpbGUgdG8gYGh0bWxgLiBJZiB5b3Ugd2FudCB0byBsb29rIGF0IHRoZSBvdXRwdXQsIGp1c3Qgb3BlbiB0aGUgYG5iLmh0bWxgIGluIHRoZSBicm93c2VyLiBBbHRlcm5hdGl2ZWx5LCBjbGljayBvbiB0aGUgIlByZXZpZXciIGJ1dHRvbiBvbiB0b3Agb2YgdGhlIGRvY3VtZW50LgoKSWYgeW91IGRlbGV0ZSBgbmIuaHRtbGAgZmlsZSwgeW91IG1heSBoYXZlIHRvIGNyZWF0ZSBhIG5ldyBgLlJtZGAgZmlsZSBhbmQgcmVzdGFydCBmcm9tIHRoZXJlLiBJZiB5b3Uga25pdCB5b3VyIGAuUm1kYCBmaWxlIHRvIGBodG1sYCwgeW91IHdpbGwgbm90IGJlIGFibGUgdG8gcmV0YWluIGFueSBvZiB0aGUgaW50ZXJhY3Rpdml0eSBpbiB0aGUgcGxvdHMuICpUaGlzIG1lYW5zIHRoZSBUQSB3aWxsIG5vdCBiZSBhYmxlIHRvIGdyYWRlIHlvdSEqCjwvZm9udD4KCgpUaGUgb2JqZWN0aXZlIG9mIHRoaXMgaG9tZXdvcmsgaXMgdG8gZ2l2ZSB5b3UgbW9yZSBwcmFjdGljZSBvbiBpbnRlcmFjdGl2ZSB2aXN1YWxpemF0aW9ucyB1c2luZyBgcGxvdGx5YCBhbmQgYGhpZ2hjaGFydGVyYC4gCgpBcyBhbHdheXMsIHJlY3JlYXRlIHRoZXNlIHZpc3VhbGl6YXRpb25zIGV4YWN0bHkuIFExIHVzZXMgYHBsb3RseWAgd2hpbGUgUTItUTUgdXNlIGBoaWdoY2hhcnRlcmAuIAoKIyMgUTEgKDMgcG9pbnRzKQoKVXNlIGBtcGdgIGRhdGEgc2V0IGZyb20gYGdncGxvdDJgIHRvIGNyZWF0ZSBhIHN0YXRpYyB2aXN1YWxpemF0aW9uIGFuZCB0aGVuIHVzZSBgZ2dwbG90bHkoKWAgdG8gY3JlYXRlIGEgbGltaXRlZCBpbnRlcmFjdGl2ZSBwbG90LgoKKipIaW50Kio6IFlvdSB3aWxsIG5lZWQgdG8gc3VwcGx5IG9ubHkgYGZyYW1lYC4gTm8gYGlkc2AgdXNlZC4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD05fQpkYXRhKG1wZywgcGFja2FnZSA9ICJnZ3Bsb3QyIikKZ2cgPC0gZ2dwbG90KG1wZywgCiAgICAgICAgICAgICBhZXMoeCA9IGN0eSwgeSA9IGh3eSwgY29sb3IgPSBjbGFzcykpICsKICBnZW9tX3BvaW50KGFlcyhmcmFtZSA9IGNsYXNzKSkgKwogIGxhYnMoeCA9ICdjdHknLAogICAgICAgeSA9ICdod3knKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJwogICkgCmdncGxvdGx5KGdnKQoKYGBgCgpGb3IgdGhlIG5leHQgZm91ciBxdWVzdGlvbnMsIHlvdSB3aWxsIHVzZSBbYGhpZ2hjaGFydGVyYF0oaHR0cHM6Ly9qa3Vuc3QuY29tL2hpZ2hjaGFydGVyLykuIAoKIyMgUTIgKDMgcG9pbnRzKQpUaGlzIGV4YW1wbGUgY3JlYXRlcyBhIGhlYXRtYXAgc2ltaWxhciB0byB0aGUgb25lIFtzaG93biBoZXJlXShodHRwczovL2prdW5zdC5jb20vaGlnaGNoYXJ0ZXIvYXJ0aWNsZXMvaGlnaGNoYXJ0ZXIuaHRtbCkuCgpVc2UgYG1wZ2AgZGF0YSBhbmQgYGhjaGFydCgpYCBmdW5jdGlvbi4gV2Ugd2FudCB0byBjcmVhdGUgYSBoZWF0bWFwIG9mIGF2ZXJhZ2UgaGlnaHdheSBtaWxlYWdlIGZvciBkaWZmZXJlbnQgYGNsYXNzYCBhbmQgYGN5bGAuIFRoaXMgcGxvdCByZW1vdmVzIGFsbCB0aGUgb2JzZXJ2YXRpb25zIHdpdGggZml2ZSBjeWxpbmRlcnMgb3Igd2l0aCBgMnNlYXRlcmAgY2xhc3MuIEFsc28gbm90ZSB0aGF0IEkgYW0gdHJlYXRpbmcgYGN5bGAgYXMgYSBjaGFyYWN0ZXIgKHN0cmluZykgdmFyaWFibGUuIFRoaXMgaXMgZXNzZW50aWFsIGZvciBjcmVhdGluZyB0aGlzIHBsb3QuCgpJIGFtIHVzaW5nIGBoY190aGVtZV81MzgoKWAuIEZ1cnRoZXJtb3JlLCB0aGUgZGVmYXVsdCBjb2xvciBpbiB0aGUgaGVhdG1hcCBpcyBibHVlLCB3aGljaCBJIGNoYW5nZWQgdXNpbmcgYGhjX2NvbG9yQXhpcygpYCBmdW5jdGlvbiB0aGF0IEkgdXNlZCBpbiB0aGUgV2VlayAxMCBoZWF0bWFwLiAKCmBgYHtyIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTZ9CmRhdGEobXBnLCBwYWNrYWdlID0gImdncGxvdDIiKQptcGckY3lsID0gYXMuY2hhcmFjdGVyKG1wZyRjeWwpCm1wZzIgPSBtcGcgJT4lCiAgc2VsZWN0KGN5bCwgY2xhc3MsIGh3eSkgJT4lCiAgZmlsdGVyKAogICFjeWwgJWluJSBjKCc1JykgJiAKICAhY2xhc3MgJWluJSBjKCcyc2VhdGVyJykKICApICU+JQogIGdyb3VwX2J5KGNsYXNzLCBjeWwpICU+JQogIHN1bW1hcmlzZSgKICAgIGh3eSA9IHJvdW5kKG1lYW4oaHd5KSwyKSwKICAgIC5ncm91cHMgPSAiZHJvcCIpIAoKc3RvcHMgPSBjb2xvcl9zdG9wcyhjb2xvcnMgPSByZXYoYygiIzAwMDAwNEZGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM1NjEwNkVGRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjQkIzNzU0RkYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0Y5OEMwQUZGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGQ0ZGQTRGRiIpKSkgIAoKaGNoYXJ0KAogICAgbXBnMiwKICAgICJoZWF0bWFwIiwKICAgIGhjYWVzKHggPSBjbGFzcywgeSA9IGN5bCwgdmFsdWUgPSBod3kpLAogICAgY29sb3JLZXkgPSAiaHd5IiwKICApICAlPiUKICBoY19jb2xvckF4aXMoCiAgICBtaW4gPSAxNSwKICAgIG1heCA9IDM1LAogICAgc3RvcHMgPSBzdG9wcykgJT4lCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lXzUzOCgpKSAlPiUKICBoY19sZWdlbmQoCiAgICBtaW4gPSAxNSwKICAgIG1heCA9IDM1LAogICAgZW5hYmxlZCA9IFRSVUUpICU+JQogIGhjX3Bsb3RPcHRpb25zKAogICAgc2VyaWVzID0gbGlzdChzaG93SW5MZWdlbmQgPSBGQUxTRSkKICApCmBgYAoKIyMgUTMgKDMgcG9pbnRzKQoKSW4gdGhlIGFib3ZlIHBsb3QsIHRoZSB0b29sdGlwIHNob3dzIGNvbmZ1c2luZyBpbmZvcm1hdGlvbi4gQmVsb3csIEkgbW9kaWZpZWQgdGhlIHRvb2x0aXAgdG8gcHJlc2VudCBtb3JlIGluZm9ybWF0aW9uLiBUaGUgY29kZSBpcyBub3QgYXQgYWxsIGNvbXBsaWNhdGVkIGFuZCByZWxpZXMgb24gdGhlIHRvb2x0aXAgY29kZSB3ZSB1c2VkIGluIFdlZWsgMTAuCgpOZXh0LCBJIHJlbW92ZWQgdGhlIFggYXhpcyB0aXRsZSBhbmQgbW9kaWZpZWQgWSBheGlzIHRpdGxlLiAKCkZpbmFsbHksIEkgYWRkZWQgYSB0aXRsZSB0byB0aGUgcGxvdC4gTm90ZSBob3cgSSB1c2VkIGZvdXIgZGlmZmVyZW50IGVtb2ppZXMgcmVsYXRlZCB0byBjYXJzLiBJdCBkb2Vzbid0IG1hdHRlciB3aGljaCBjYXIgZW1vamlzIHlvdSB1c2UgYXMgbG9uZyBhcyB0aGV5IGFyZSByZWxhdGVkIHRvIGF1dG9tb2JpbGVzLgoKCmBgYHtyIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTZ9CmRhdGEobXBnLCBwYWNrYWdlID0gImdncGxvdDIiKQptcGckY3lsID0gYXMuY2hhcmFjdGVyKG1wZyRjeWwpCm1wZzIgPSBtcGcgJT4lCiAgc2VsZWN0KGN5bCwgY2xhc3MsIGh3eSkgJT4lCiAgZmlsdGVyKAogICFjeWwgJWluJSBjKCc1JykgJiAKICAhY2xhc3MgJWluJSBjKCcyc2VhdGVyJykKICApICU+JQogIGdyb3VwX2J5KGNsYXNzLCBjeWwpICU+JQogICAgc3VtbWFyaXNlKAogICAgaHd5ID0gcm91bmQobWVhbihod3kpLDIpLAogICAgLmdyb3VwcyA9ICJkcm9wIikgCgpzdG9wcyA9IGNvbG9yX3N0b3BzKGNvbG9ycyA9IHJldihjKCIjMDAwMDA0RkYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzU2MTA2RUZGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNCQjM3NTRGRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRjk4QzBBRkYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0ZDRkZBNEZGIikpKSAgCgpmbnRsdHAgPC0gSlMoImZ1bmN0aW9uKCl7CiAgICAgICAgICAgICAgICAgIHJldHVybiAnRm9yIGNsYXNzICcgKyB0aGlzLnNlcmllcy54QXhpcy5jYXRlZ29yaWVzW3RoaXMucG9pbnQueF0gKyAnIHdpdGggJyArCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNlcmllcy55QXhpcy5jYXRlZ29yaWVzW3RoaXMucG9pbnQueV0gKyAnIGN5bGluZGVycycgKyAnOiA8Yj4nICsKICAgICAgICAgICAgICAgICAgICAgICAgIEhpZ2hjaGFydHMubnVtYmVyRm9ybWF0KHRoaXMucG9pbnQudmFsdWUsIDIpKyc8L2I+JyArICcgbXBnJzsKICAgICAgICAgICAgICAgOyB9IikKCmhjaGFydCgKICAgIG1wZzIsCiAgICAiaGVhdG1hcCIsCiAgICBoY2Flcyh4ID0gY2xhc3MsIHkgPSBjeWwsIHZhbHVlID0gaHd5KSwKICAgIGNvbG9yS2V5ID0gImh3eSIsCiAgICBuYW1lID0gIkhpZ2h3YXkgTWlsZWFnZSIKICApICAlPiUKICBoY19jb2xvckF4aXMoCiAgICBtaW4gPSAxNSwKICAgIG1heCA9IDM1LAogICAgc3RvcHMgPSBzdG9wcykgJT4lCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lXzUzOCgpKSAlPiUKICBoY19sZWdlbmQoCiAgICBtaW4gPSAxNSwKICAgIG1heCA9IDM1LAogICAgZW5hYmxlZCA9IFRSVUUpICU+JQogIGhjX3Bsb3RPcHRpb25zKAogICAgc2VyaWVzID0gbGlzdChzaG93SW5MZWdlbmQgPSBGQUxTRSkKICApICU+JQogIGhjX3RpdGxlKHRleHQgPSAiSGlnaHdheSBNaWxlYWdlIERlY3JlYXNlcyBhY3Jvc3MgYWxsIHRoZSAg8J+alyDwn5qZIPCfj44g8J+buyBhcyB0aGUgTnVtYmVyIG9mIEN5bGluZGVycyBJbmNyZWFzZXMiLAogICAgICAgICAgIHN0eWxlID0gbGlzdChjb2xvciA9ICJibGFjayIsIHdlaWdodCA9ICJib2xkIikpICU+JQogIGhjX3lBeGlzKHRpdGxlID0gbGlzdCh0ZXh0ID0gIk51bWJlciBvZiBDeWxpbmRlcnMiKSkgJT4lCiAgaGNfeEF4aXModGl0bGUgPSBsaXN0KHRleHQgPSAiIikpICU+JQogIGhjX3Rvb2x0aXAoZm9ybWF0dGVyID0gZm50bHRwKQoKYGBgCgoKIyMgUTQgKDMgcG9pbnRzKQoKRm9yIHRoaXMgZXhhbXBsZSwgdXNlIGEgcmFuZG9tbHkgc2VsZWN0ZWQgc3Vic2V0IG9mIGBkaWFtb25kc2AgZGF0YSBzZXQgZnJvbSBgZ2dwbG90MmA6CgpgYGB7ciBlY2hvPVRSVUV9Cj9kaWFtb25kcwpzZXQuc2VlZCgyMDIwKQpkMSA9IGRpYW1vbmRzW3NhbXBsZShucm93KGRpYW1vbmRzKSwgMTAwMCksXQpgYGAKCk5leHQgdXNlIGBkMWAgdG8gY3JlYXRlIHRoZSBmb2xsb3dpbmcgcGxvdC4gCgpJIGhhdmUgdXNlZCBgaGNfdGhlbWVfZmxhdCgpYCBmb3IgdGhpcyBwbG90LiAqKlBsZWFzZSB1c2UgdGhpcyB0aGVtZSBmb3IgeW91ciBwbG90IHRvbyEqKgpZb3UgY2FuIGFkZCBhIHRoZW1lIHRvIHRoZSBwbG90IHVzaW5nIGBoY19hZGRfdGhlbWUoKWAgZnVuY3Rpb24uIFdoZXJldmVyIHRoZSB3b3JkIGRpYW1vbmQgYXBwZWFyZWQgaW4gdGhlIHBsb3QsIEkgcmVwbGFjZWQgaXQgd2l0aCB0aGUgZGlhbW9uZCBlbW9qaS4KClBvaW50IGNvbG9ycyBpbiB0aGlzIGdyYXBoIGFyZSBtYXBwZWQgdG8gYGNsYXJpdHlgLiBDaGVjayBvdXQgYWxsIHRoZSB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIHNldCBieSB0eXBpbmcgYD9kaWFtb25kc2AgaW4gdGhlIGNvbnNvbGUuCgpgYGB7ciBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD02fQoKaGNoYXJ0KAogIGQxLAogICJzY2F0dGVyIiwKICBoY2Flcyh4PWNhcmF0LCB5PXByaWNlLCBncm91cD1jbGFyaXR5KQopICU+JQogIGhjX2FkZF90aGVtZShoY190aGVtZV9mbGF0KCkpICU+JQogIGhjX3hBeGlzKAogICAgdGl0bGUgPSBsaXN0KHRleHQgPSAiV2VpZ2h0IG9mIPCfko4gaW4gQ2FyYXRzIikpICU+JQogIGhjX3lBeGlzKAogICAgdGl0bGUgPSBsaXN0KHRleHQgPSAiUHJpY2Ugb2Yg8J+SjiIpKSAlPiUKICBoY190aXRsZSh0ZXh0ID0gIlZhcmlhdGlvbiBpbiBQcmljZXMgZm9yIPCfko4gSW5jcmVhc2VzIHdpdGggQ2FyYXRzIiwKICAgICAgICAgICBzdHlsZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAiYm9sZCIpKQoKCmBgYAoKCiMjIFE1ICgzIHBvaW50cykKClJlY3JlYXRlIHRoZSBwbG90IGluIFEyIHVzaW5nIGBoY2hhcnQoKWAuIEkgdXNlZCBgaGNfdGhlbWVfZWNvbm9taXN0KClgLiBZb3UgY2FuIHVzZSBhbnkgdGhlbWUgeW91IHdhbnQuIFlvdSBjYW4gY2hlY2sgb3V0IHRoZSB0aGVtZXMgW2hlcmVdKGh0dHBzOi8vamt1bnN0LmNvbS9oaWdoY2hhcnRlci9hcnRpY2xlcy90aGVtZXMuaHRtbCkuIEkgdXNlZCBgZWNvbm9taWNzYCBkYXRhc2V0IGZyb20gYGdncGxvdDJgLiBMZWFybiBtb3JlIGFib3V0IHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgYnkgdHlwaW5nIGA/ZWNvbm9taWNzYCBpbiB0aGUgY29uc29sZS4KCmBgYHtyIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTZ9CmRhdGEoZWNvbm9taWNzLCBwYWNrYWdlID0gImdncGxvdDIiKSAKCmVjb24yID0gZWNvbm9taWNzICU+JQogIHNlbGVjdChkYXRlLCB1bmVtcGxveSkKCmhjaGFydCgKICBlY29uMiwKICAibGluZSIsCiAgaGNhZXMoeD1kYXRlLCB5PXVuZW1wbG95KSkgJT4lCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2Vjb25vbWlzdCgpKSAlPiUKICBoY194QXhpcygKICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gIkRhdGUiKSkgJT4lCiAgaGNfeUF4aXMoCiAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICJVbmVtcGxveW1lbnQgaW4gJzAwMCIpLAogICAgbWluID0gMjAwMCwKICAgIG1heCA9IDE2MDAwLAogICAgYWxpZ25UaWNrcyA9IEZBTFNFLAogICAgdGlja0ludGVydmFsID0gMjAwMCkgJT4lCiAgaGNfdGl0bGUodGV4dCA9ICJVbmVtcGxveW1lbnQgUGVha2VkIGFmdGVyIHRoZSBGaW5hbmNpYWwgQ3Jpc2lzIiwKICAgICAgICAgICBzdHlsZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3ZWlnaHQgPSAiYm9sZCIsIGZvbnRTaXplID0gMTgpLAogICAgICAgICAgIGFsaWduID0gJ2NlbnRlcicpICU+JQogIGhjX3Rvb2x0aXAocG9pbnRGb3JtYXQgPSAiPGRpdiBzdHlsZT1maWxsOiM2Nzk0YTc+4pePPC9kaXY+IFVuZW1wbG95bWVudDogPGI+e3BvaW50Lnl9PC9iPiIpCgoKYGBgCgoKIyMgQm9udXMgcGxvdCAoTm90IGdyYWRlZCkKClRoaXMgaXMgdGhlIHNhbWUgcGxvdCBhcyBhYm92ZSBleGNlcHQgaWYgeW91IGhvdmVyIG1vdXNlIHBvaW50ZXIgb3ZlciB0aGUgcGVhayBvZiB1bmVtcGxveW1lbnQsIHRoZSB0b29sdGlwIHdpbGwgc2hvdyBtb3JlIGluZm9ybWF0aW9uLiBPbmNlIGFnYWluLCB0aGlzIGlzIGEgc2ltcGxlIHRyaWNrIGFuZCBkb2Vzbid0IHJlcXVpcmUgYW55IGFkdmFuY2VkIGNvZGluZy4gCgoKYGBge3IgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9Nn0KCgpgYGAKCgo=